import { Mesh, LinearFilter, Texture, PlaneGeometry, AlwaysStencilFunc, ReplaceStencilOp, NotEqualStencilFunc, KeepStencilOp, WebGLRenderer, NeverStencilFunc} from "three";
import GeoUtils from "../../utils/GeoUtils";
import Helper from "../../utils/Helper";
import { App } from "../../Engine";
import TilePort from "../../component/models/TilePort";
import MeshUtil from "../../renderExtension/utils/MeshUtil";
import Events from "../../application/constants/Events";
import ParseBundleTile from "../utils/ParseBundleTile";
import Const from "../../application/constants/Const";
import { CustomMeshBasicMaterial } from "../../renderExtension/Material/CustomMaterial";
/**
 * 基础瓦片
 */
export default class BaseTile extends Mesh implements TilePort{
    protected url: string;
    // protected demScale: number;
    protected options: any;
    protected loadcallback;
    public material: CustomMeshBasicMaterial;
    private imageRequest;
    private lrcz: number;
    private static defaultTexture: Texture; //默认的纹理
    private static tileGeometry: PlaneGeometry;

    /**
     * 基础瓦片的构造函数
     * @param options 构造函数的参数
     * options.url 影像底图的url
     * options.useDefaultTexture 是否使用默认瓦片底图，当瓦片的影像纹理请求还没有成功的时候，瓦片先使用默认瓦片底图
     * options.loaded 纹理图片加载成功后的回调函数
     * options.curzoom 当前地图的层级
     * options.lrc 瓦片行列号的json数据
     * options.zIndex 为了避免深度冲突，调整高度值
     * options.isAdditionalLayer 是否是附加图层。如果是附件图层，没有数据的瓦片不显示。这样做是为了避免附件图层中没有数据的瓦片会遮挡下面的图层
     * options.colorSpace 颜色空间，默认值是'', 还有其他参数'srgb', 'linear'
     */
    constructor(options: any) {
        super(undefined, undefined);       
        this.options = options;        
        this.loadcallback = options.loaded;
        
        this.setTile(options); //设置瓦片的位置和图片的url
        this.setGeometry(options);
        this.setMaterial(options);

        Helper.enablePolygonOffset(this.material, App.getInstance().options.Map.maxZoom - this.lrcz, options.zIndex);
    }

    private setTile(options){ //设置瓦片的位置和图片的url
        let cx = GeoUtils.getCDevX(options.lrc.x, options.lrc.z, 0.5);
        let cy = GeoUtils.getRDevY(options.lrc.y, options.lrc.z, 0.5);
        let lrcx = options.lrc.x;
        let lrcy = options.lrc.y;
        this.lrcz = options.lrc.z;   

        this.position.set(cx, cy, 0);
  
        let tileRowCount = Math.pow(2, this.lrcz); //当前层级横向和纵向瓦片的数量
        
        while(lrcx < 0){
            lrcx = lrcx + tileRowCount;
        }
        if ((lrcx >= tileRowCount)) {
            lrcx = (lrcx%tileRowCount);
        }
        
        this.url = Helper.getTileUrl(this.options.url, lrcx, lrcy, this.lrcz+'', (this.options.urlDecimal === undefined) ? true : this.options.urlDecimal);//options.url;
        return true;
    }

    private setGeometry(options){
        let tileWidth = GeoUtils.getTileWidth(options.curzoom);

        this.geometry = new PlaneGeometry(tileWidth, tileWidth, 10, 10);

        if (!BaseTile.tileGeometry || BaseTile.tileGeometry['tileWidth'] != tileWidth) { //一个层级只使用一个几何体
            BaseTile.tileGeometry = new PlaneGeometry(tileWidth, tileWidth, 1, 1);
            BaseTile.tileGeometry['tileWidth'] = tileWidth;
        }
        this.geometry = BaseTile.tileGeometry;
        // App.getInstance().fireEvent(Events.AdjustModelHeight, this); //通知其他模型根据这个瓦片的数据调整高度
    }

    public updateVisibility(){
        this.material.stencilRef = Const.StencilRefValue.BaseTileRef;
        this.material.stencilFunc = NotEqualStencilFunc;
        this.material.stencilFail = KeepStencilOp;
        this.material.stencilZFail = KeepStencilOp;
        this.material.stencilZPass = KeepStencilOp;
        this.material.needsUpdate = true;
    }

    public restoreVisibility(){
        this.material.stencilRef = Const.StencilRefValue.BaseTileRef;
        this.material.stencilFunc = AlwaysStencilFunc;
        this.material.stencilFail = ReplaceStencilOp;
        this.material.stencilZFail = ReplaceStencilOp;
        this.material.stencilZPass = ReplaceStencilOp;
        this.material.needsUpdate = true;
    }

    private setMaterial(options){
        let materialParam = {
            coreParameters: {
                depthTest: true,

                //设置模版缓冲区，用2覆盖模版缓冲区
                stencilWrite: true,
				stencilRef: Const.StencilRefValue.BaseTileRef,
                stencilFuncMask: 0xff,
				stencilFunc: AlwaysStencilFunc,
				stencilFail: ReplaceStencilOp,
				stencilZFail: ReplaceStencilOp,
				stencilZPass: ReplaceStencilOp,
            },
            identity: 'baseTileMaterial'
        };

        this.material = new CustomMeshBasicMaterial(materialParam);
        if (!BaseTile.defaultTexture) {
            let defaultImage = ''
            BaseTile.defaultTexture = Helper.createTexture(defaultImage);
        }
        if (options.useDefaultTexture) {
            this.material.map = BaseTile.defaultTexture;
            this.material.color.set(1, 1, 1);
        }else{
            this.material.color.set(App.getInstance().options.Map.tileDefaultColor);
            // this.material.color.set('');
        }

        if(options.isAdditionalLayer){ //可选图层的瓦片数据可能只在一个区域内，设置为透明度是为了避免边缘瓦片只有部分区域有效，其他区域为透明。如果不设置为透明度，会出现一片黑色
            this.material.transparent = true;
            this.material.opacity = 0;
        }

        if(options.isBackgroundLayer){ //如果该图层是背景，关闭深度检测
             this.material.depthTest = false;
        }else{
            this.material.depthTest = true;
        }

        let parseBundle:ParseBundleTile =  options['parseBundle'];
        if (!parseBundle) { //松散型瓦片
            this.requestDom(this.url);
        }else{ //紧凑型瓦片
            let self = this;
            parseBundle.getTile(options.lrc.x, options.lrc.y, options.lrc.z, function (imageData) {
                let imageTexture = Helper.createTextureWithData(imageData, self.callbackTexture.bind(self));
                self.imageRequest = imageTexture['imageLoader'];
            });
        }
        this.material.needsUpdate = true;
    }

    private requestDom(url) {
        if (!url) return;
        let imageTexture = Helper.createTexture(url, this.callbackTexture.bind(this), true);
        this.imageRequest = imageTexture['imageLoader'];
    }

    private callbackTexture(isSuccess, texture: Texture){
        if (isSuccess) {
            // this.visible = true;
            texture.magFilter = LinearFilter;
            texture.minFilter = LinearFilter;
            texture.colorSpace = this.options.colorSpace; 
            this.material.map = texture;
            this.material.transparent = false;
            if(this.options.isAdditionalLayer){//可选图层的瓦片数据可能只在一个区域内，设置为透明度是为了避免边缘瓦片只有部分区域有效，其他区域为透明。如果不设置为透明度，会出现一片黑色
                this.material.transparent = true;
                this.material.opacity = 1;
            }
            this.material.needsUpdate = true;
            this.material.color.set(1, 1, 1);
            // scope.material.depthTest = false;
            
            this.imageRequest = null;
        }else{
            if(this.options.isAdditionalLayer){
                MeshUtil.dispose(this);
            }
        }

        if (this.loadcallback){
            this.loadcallback(this);
            this.restoreVisibility();
        } 

        if(!this.options.isAdditionalLayer){ //非附加图层，每次创建瓦片都要向外发送广播通知
            App.getInstance().fireEvent(Events.AddTile); 
        }
    }

    public cancleNetTask(){
        if (!this.imageRequest) {
            return;
        }

        try {
            if(this.imageRequest instanceof XMLHttpRequest){
                this.imageRequest.abort();
                this.imageRequest.onload = null;
                this.imageRequest.onerror = null;
                this.imageRequest = null;
            }else{
                this.imageRequest.src = '';
            }
            
        } catch (error) {
        }
    }

    public dispose() {
        this.cancleNetTask();
        MeshUtil.dispose(this);
    }

    public setCut(clapData: {isOpenClap: boolean, clapPointArray: [], clapPointCount: number, renderSide: number}) {
        this.material['setCut'](clapData);
    }

}